﻿using NPOI.HSSF.UserModel;
using NPOI.HSSF.Util;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;

namespace FwProject.Comm.ExcelUtil
{
    public class ExcelHelper
    {
        private string fileName = null; //文件名
        private IWorkbook workbook = null;
        /// <summary>
        /// 获取定义的特性值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="provider"></param>
        /// <returns></returns>
        public static T GetAttribute<T>(ICustomAttributeProvider provider)
        where T : Attribute
        {
            return provider.GetCustomAttributes(typeof(T), true)
                .Cast<T>().ToArray().FirstOrDefault();
        }
        public void OutDataToExcel<T>(List<T> list, string path)
        {
            if (list.Count == 0) return;
            string title = string.Empty;
            int i = 0;
            int rowCountNumber = 0;
            ISheet sheet = null;
            fileName = path;

            if (fileName.IndexOf(".xlsx") > 0) // 2007版本
                workbook = new XSSFWorkbook();
            else if (fileName.IndexOf(".xls") > 0) // 2003版本
                workbook = new HSSFWorkbook();



            using (FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                try
                {
                    var t = list.First().GetType();//获取列表的类的属性
                    var properties = t.GetProperties().Where(x => GetAttribute<ExcelDateMemberAttribute>(x) != null);//筛选出需要导出的字段
                    title = GetAttribute<DisplayNameAttribute>(t)?.DisplayName;///excel 标题名称

                    if (workbook != null)
                    {
                        if (sheet == null) //如果没有找到指定的sheetName对应的sheet，则尝试获取第一个sheet
                        {
                            sheet = workbook.CreateSheet(title);///创建一个sheet
                        }
                    }

                    int Colnum = properties.Count();//表格列数 
                    int Rownum = list.Count;//表格行数 
                    if (list.Count > 0) //写入DataTable的列名
                    {
                        IRow row = sheet.CreateRow(0);
                        ICell cell = row.CreateCell(0);
                        cell.SetCellValue($"{title}:Excel导出时间：{DateTime.Now.ToString("yyyy-MM-dd")}");

                        ICellStyle style = workbook.CreateCellStyle();
                        style.FillForegroundColor = HSSFColor.Red.Index;

                        //设置单元格的样式：水平对齐居中
                        style.Alignment = HorizontalAlignment.Center;
                        //新建一个字体样式对象
                        IFont font = workbook.CreateFont();

                        font.FontHeightInPoints = 14;
                        //设置字体加粗样式
                        font.Boldweight = short.MaxValue;
                        font.FontName = "微软雅黑";
                        font.Color = HSSFColor.Red.Index;
                        //使用SetFont方法将字体样式添加到单元格样式中 
                        style.SetFont(font);
                        cell.CellStyle = style;
                        //第一行合并
                        sheet.AddMergedRegion(new CellRangeAddress(0, 0, 0, properties.Count()));
                        rowCountNumber = 1;
                    }
                    else
                    {
                        rowCountNumber = 0;
                    }
                    IRow cellrow = sheet.CreateRow(rowCountNumber++);
                    Dictionary<int, decimal> dic = new Dictionary<int, decimal>();
                    foreach (var item in properties)
                    {
                        var mutType = item.GetType();
                        var pro = GetAttribute<ExcelDateMemberAttribute>(item);
                        //目前系统就支持一个模型
                        if (pro?.IsMultiRow == true)
                        {
                            if (pro?.ListOne == true)
                            {
                                var colName = GetAttribute<DisplayNameAttribute>(item)?.DisplayName;
                                if (pro.IsSum)
                                    dic.Add(i, 0);

                                cellrow.CreateCell(i).SetCellValue(colName);

                                i++;
                            }
                            else
                            {
                                var type = Type.GetType(item.PropertyType.AssemblyQualifiedName);
                                var mutproperties = type.GetGenericArguments()[0].GetProperties().Where(x => GetAttribute<ExcelDateMemberAttribute>(x) != null);
                                foreach (var mutitem in mutproperties)
                                {
                                    var colName = GetAttribute<DisplayNameAttribute>(mutitem)?.DisplayName;

                                    if (GetAttribute<ExcelDateMemberAttribute>(mutitem).IsSum)
                                        dic.Add(i, 0);

                                    cellrow.CreateCell(i).SetCellValue(colName);
                                    i++;
                                }
                            }

                        }
                        else
                        {
                            if (pro?.IsClass == true)
                            {
                                var type = Type.GetType(item.PropertyType.AssemblyQualifiedName);
                                var mutproperties = type.GetProperties().Where(x => GetAttribute<ExcelDateMemberAttribute>(x) != null);
                                foreach (var mutitem in mutproperties)
                                {
                                    var colName = GetAttribute<DisplayNameAttribute>(mutitem)?.DisplayName;
                                    if (GetAttribute<ExcelDateMemberAttribute>(mutitem).IsSum)
                                        dic.Add(i, 0);


                                    cellrow.CreateCell(i).SetCellValue(colName);
                                    i++;
                                }
                            }
                            else
                            {
                                var colName = GetAttribute<DisplayNameAttribute>(item)?.DisplayName;
                                cellrow.CreateCell(i).SetCellValue(colName);

                                if (pro.IsSum)
                                    dic.Add(i, 0);

                                i++;
                            }


                        }

                    }
               
                    foreach (var rowdata in list)
                    {

                        IRow celldatarow = sheet.CreateRow(rowCountNumber);
                        int tempRow = 0;
                        int cellI = 0;
                        int Merged = 0;
                        bool isMut = false;
                        foreach (var item in properties)
                        {
                            int temp = 0;
                            if (GetAttribute<ExcelDateMemberAttribute>(item)?.IsMultiRow == true)
                            {
                                object objevalue = item.GetValue(rowdata, null);
                                IEnumerable<object> a = objevalue as IEnumerable<object>;
                         
                                    if (a != null)
                                    {
                                        temp = a.Count();
                                        if (temp > 0)
                                        {
                                            isMut = true;
                                            if (temp >= Merged)
                                                Merged = temp;
                                        }
                                    }
                            }
                        }

                        foreach (var item in properties)
                        {
                            //反射遍历添加数据如果是多条
                            if (GetAttribute<ExcelDateMemberAttribute>(item)?.IsMultiRow == true)
                            {
                                //是一个多列的情况
                                object objevalue = item.GetValue(rowdata, null);

                                IEnumerable<object> a = objevalue as IEnumerable<object>;

                                tempRow = rowCountNumber;

                                if (objevalue != null)
                                {
                                    var cellrows = 0;
                                    var temp = 0;
                                    foreach (var model in a)     //循环list
                                    {
                                        cellrows++;
                                        if (temp!=0) {
                                            tempRow++;
                                        } 
                                        IRow rowcellrow = null;
                                        if (sheet.GetRow(tempRow) == null)
                                        {
                                            rowcellrow = sheet.CreateRow(tempRow);
                                        }
                                        else
                                        {
                                            rowcellrow = sheet.GetRow(tempRow);
                                        }


                                        if (GetAttribute<ExcelDateMemberAttribute>(item)?.ListOne == true)//简单对象
                                        {
                                            string value = model.ToString();
                                            rowcellrow.CreateCell(cellI).SetCellValue(value);
                                            if (dic.ContainsKey(cellI))
                                            {
                                                dic[cellI] = dic[cellI] + Convert.ToDecimal(value);
                                            }

                                            cellI++;
                                        }
                                        else
                                        {
                                          
                                            temp = cellI;
                                            var listModel = model.GetType(); ;//获取当前对象类型
                                            var mutproperties = listModel.GetProperties().Where(x => GetAttribute<ExcelDateMemberAttribute>(x) != null);
                                            foreach (var mutitem in mutproperties)
                                            {
                                                var value = mutitem.GetValue(model, null);
                                                string ss = value == null ? "" : value.ToString();
                                                rowcellrow.CreateCell(temp).SetCellValue(ss);

                                                if (dic.ContainsKey(temp))
                                                {
                                                    dic[temp] = dic[temp] + Convert.ToDecimal(value);
                                                }

                                                temp++;
                                            }
                                        }

                                      
                                    }
                                    cellI = cellI + temp ;

                                }

                            }
                            else
                            {
                                object value = item.GetValue(rowdata, null);
                                if (GetAttribute<ExcelDateMemberAttribute>(item)?.IsClass == true)
                                {
                                    var mutproperties = value.GetType().GetProperties().Where(x => GetAttribute<ExcelDateMemberAttribute>(x) != null);
                                    foreach (var mutitem in mutproperties)
                                    {
                                        object tempvalue = mutitem.GetValue(value, null);
                                        string ss = tempvalue == null ? "" : tempvalue.ToString();
                                        celldatarow.CreateCell(cellI).SetCellValue(ss);

                                        if (dic.ContainsKey(cellI))
                                        {
                                            dic[cellI] = dic[cellI] + Convert.ToDecimal(ss);
                                        }


                                        if (GetAttribute<ExcelDateMemberAttribute>(item)?.IsMerged == true)
                                        {
                                            if (isMut)
                                            {
                                                sheet.AddMergedRegion(new CellRangeAddress(rowCountNumber, rowCountNumber + Merged, cellI, cellI));
                                            }

                                        }
                                        cellI++;

                                    }

                                }
                                else
                                {
                                    string ss = value == null ? "" : value.ToString();
                                    celldatarow.CreateCell(cellI).SetCellValue(ss);

                                    if (dic.ContainsKey(cellI))
                                    {
                                        dic[cellI] = dic[cellI] + Convert.ToDecimal(ss);
                                    }

                                    if (GetAttribute<ExcelDateMemberAttribute>(item)?.IsMerged == true)
                                    {
                                        if (isMut)
                                        {
                                            if(Merged>1)
                                            sheet.AddMergedRegion(new CellRangeAddress(rowCountNumber, rowCountNumber + Merged-1, cellI, cellI));
                                        }
                                    }

                                    cellI++;
                                }

                            }
                        }
                        if(tempRow!=0)
                            rowCountNumber = tempRow;

                        rowCountNumber++;
                    }
                    var Sumcelldatarow = sheet.CreateRow(rowCountNumber);
                    foreach (var item in dic)
                    {
                        Sumcelldatarow.CreateCell(item.Key).SetCellValue(item.Value.ToString());
                    }

                    workbook.Write(fs);
                }
                catch (Exception exe)
                {

                    workbook.Close();
                    fs.Close();
                    System.Console.WriteLine($"ExcelHelper:{exe.ToString()}");
                }
                finally
                {

                    workbook.Close();
                    fs.Close();
                }
            }


        }
    }
}
